////////////
//
// 验证出来 自定义删除器的shared_ptr对象在销毁函数中不能再调用自己的 shared_from_this 函数, 否则会引起崩溃
//
#include <algorithm>
#include <arpa/inet.h>
#include <functional>
#include <map>
#include <memory>
#include <set>
#include <string.h>
#include <string>
#include <strings.h>

class sdns_cache_obj : public std::enable_shared_from_this<sdns_cache_obj> {
public:
    /**
     * @brief 默认构造函数 必须有 否则作为map
     *
     * @param group_key 所属的group key, 用于用于销毁时在group中查找清理对象
     */
    sdns_cache_obj(const std::string& group_key)
        : group_key_(group_key)
    {
        printf("@@@@@@@@@@@@ create obj=%p\n", this);
    }
    ~sdns_cache_obj()
    {
        printf("@@@@@@@@@@@@ delete obj=%p\n", this);
    }

    bool create(const std::string& subnet_ip)
    {
        data_ = subnet_ip;
        return true;
    }

    std::string get_key_str() const { return std::string("mmmmmmmmm"); }

    const std::string& get_group_key() const { return group_key_; }

public:
    bool operator<(const sdns_cache_obj& rhs) const
    {
        return data_.compare(rhs.data_) < 0;
    }

private:
    std::string data_;      // 要管理的数据
    std::string group_key_; // 对应的分组key
};

template <typename T>
struct set_shardptr_compare {
    bool operator()(const std::weak_ptr<T>& lhs,
        const std::weak_ptr<T>& rhs) const
    {
        return *(lhs.lock()) < *(rhs.lock());
    }
};

typedef std::set<std::weak_ptr<sdns_cache_obj>,
    set_shardptr_compare<sdns_cache_obj>>
    SET_SHARE;
typedef std::map<std::string, SET_SHARE> MAP_OBJ;

class sdns_cache_group : public std::enable_shared_from_this<sdns_cache_group> {
public:
    sdns_cache_group()
    {
    }

    ~sdns_cache_group() { }

    std::shared_ptr<sdns_cache_obj> create_obj(
        const std::string& key)
    {
        std::shared_ptr<sdns_cache_obj> ret = std::shared_ptr<sdns_cache_obj>(
            new sdns_cache_obj(key),
            std::bind(&sdns_cache_group::weak_delete_cbk,
                std::weak_ptr<sdns_cache_group>(shared_from_this()),
                std::placeholders::_1));
        return ret;
    }

    bool add(const std::string& domain, unsigned short type,
        const std::string& subnet_ip)
    {
        bool bret = false;
        auto tmp = create_obj(create_key(domain, type));
        if (tmp->create(subnet_ip)) {
            bret = add(tmp);
        }
        return bret;
    }

    bool add(std::shared_ptr<sdns_cache_obj>& obj)
    {
        const std::string& key = obj->get_group_key();
        auto it = records_.find(key);
        if (it == records_.end()) {
            SET_SHARE tmp;
            records_[key] = tmp;
            it = records_.find(key);
        }
        if (it == records_.end() || false == it->second.insert(obj).second) {
            auto v = it->second.lower_bound(obj);
            auto tt = (*v).lock(); // 转为shared_ptr
            if (tt) {
                printf("find duplicate info %s(%s), v.subnet=%s,\n", key.c_str(),
                    obj->get_key_str().c_str(), tt->get_key_str().c_str());
            } else {
                printf("find duplicate info %s\n", key.c_str());
            }
            return false;
        }
        return true;
    }

    std::string create_key(const std::string& name, unsigned short qtype)
    {
        std::string domain(name);
        if (domain[domain.size() - 1] != '.') {
            domain.append(".");
        }
        char buf[1024];
        bzero(buf, 1024);
        snprintf(buf, 1024, "%s_%u", domain.c_str(), qtype);
        return std::string(buf);
    }

    static void weak_delete_cbk(std::weak_ptr<sdns_cache_group>& gp,
        sdns_cache_obj* obj)
    {
        std::shared_ptr<sdns_cache_group> group(gp.lock());
        if (group) {
            group->delete_cbk(obj);
            printf("xxxxxxxxxxxxxxxxxxxx remove obj=%p\n", obj);
        } else { // 已经被销毁了
            printf("xxxxxxxxxxxxxxxxxx group had been destroyed.\n");
        }
        delete obj; // 因为自定义了删除器所以需要自己销毁对象
    }

    void delete_cbk(sdns_cache_obj* obj)
    {
        auto it = records_.find(obj->get_group_key());
        if (it != records_.end()) {
            //TODO 注意，在析构函数中调用shared_from_this将引起程序的崩溃
            auto v = it->second.find(obj->shared_from_this());
            if (v != it->second.end()) {
                it->second.erase(v);
                if (it->second.empty()) {
                    records_.erase(it);
                }
            } else {
                printf("@@@@@@@@@@@@ not find obj=%p.\n", obj);
            }
        }
    }

private:
    MAP_OBJ records_; // 记录数
};

int main()
{
    {
        auto gp=std::make_shared<sdns_cache_group>();
        gp->add("www.baidu.com", 1, "1.1.1.1");
    }
    return 0;
}
